package com.mm.dictionary.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mm.common.config.FileProperties;
import com.mm.common.config.RedisProperties;
import com.mm.common.domain.po.Result;
import com.mm.common.enums.ResultCode;
import com.mm.common.utils.cacheUtil.CacheClient;
import com.mm.common.utils.DataUtils;
import com.mm.common.utils.SessionHolder;
import com.mm.dictionary.config.DictionaryProperties;
import com.mm.dictionary.domain.po.Count;
import com.mm.dictionary.domain.po.Word;
import com.mm.dictionary.mapper.WordMapper;
import com.mm.dictionary.utils.translate.WordUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import opennlp.tools.postag.POSModel;
import opennlp.tools.postag.POSTaggerME;
import opennlp.tools.tokenize.TokenizerME;
import opennlp.tools.tokenize.TokenizerModel;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: 9.English_dictionary
 * @BelongsPackage: com.example.english_dictionary.service.impl
 * @Author : 游在海里的鱼
 * @CreateTime : 2024-05-13  21:28
 * @Version : 1.0
 * @ClassName : TODO
 * @Description : TODO
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WordServiceImpl extends ServiceImpl<WordMapper, Word> implements IWordService {
    private final WordMapper wordMapper;
    private final RedisProperties redisProperties;
    private final FileProperties fileProperties;
    private final DictionaryProperties dicProperties;
    private final CacheClient cacheClient;


    public Result analysisText(String text){

        if(StrUtil.isBlank(text)){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }

        //分解大驼峰，小驼峰，还有-和_
        text = text.replaceAll("[_-]|(?<=[a-z])(?=[A-Z])", " ");

        //分词+分析词性
        TokenizerME tokenizer = null;
        POSModel posModel = null;
        try {
            //加载分词标注模型
            TokenizerModel tokenizerModel = new TokenizerModel(new FileInputStream(fileProperties.save_file_url +"/modal/en-token.bin"));
            tokenizer = new TokenizerME(tokenizerModel);
            // 加载词性标注模型
            posModel = new POSModel(new FileInputStream(fileProperties.save_file_url +"/modal/en-pos-maxent.bin"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        POSTaggerME posTagger = new POSTaggerME(posModel);
        String[] tokens = tokenizer.tokenize(text);
        String[] tags = posTagger.tag(tokens);

        //处理单词
        Map<String,Word> wordMap = new HashMap<>();
        for (int i = 0; i < tokens.length; i++) {
            Word word = wordMap.get(tokens[i]);
            if(word != null){
                word.addCount();
            }else {
                if(DataUtils.isWordInvalid(tokens[i])){
                    continue;
                }

                word = new Word();
                word.setUid(SessionHolder.getUser());
                word.setWord(WordUtils.NNPTransition(tokens[i],tags[i]));
                word.setNature(convertTagToName(tags[i]));
                word.setPhonetic(WordUtils.phonetic(tokens[i]));
                word.setTranslation(WordUtils.translate(tokens[i]));
                initWord(word);
                wordMap.put(tokens[i],word);
            }
        }
        //存数据库
        List<Word> wordList = new ArrayList<>(wordMap.values());
        for(Word word:wordList){
            if(wordMapper.updateCountInt(word) <= 0){
                saveOrUpdate(word);
            }else {
                word.setRemark(lambdaQuery().eq(Word::getUid, SessionHolder.getUser()).eq(Word::getWord,word.getWord()).one().getRemark());
            }
        }
        //删除缓存
        cacheClient.removeCaches(redisProperties.cache_word_byTime_pre+ SessionHolder.getUser()+":*");
        cacheClient.removeCaches(redisProperties.cache_word_byCount_pre+ SessionHolder.getUser()+":*");
        cacheClient.removeCache(redisProperties.cache_word_page_pre+ SessionHolder.getUser());
        return Result.success(JSONUtil.toJsonStr(wordList));
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取单词表，根据时间
    **/
    public Result getWordsByTime(Integer page){
        if(DataUtils.isNaturalNumInvalid(page)){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }
        String keyPre =redisProperties.cache_word_byTime_pre+ SessionHolder.getUser()+":";
        List<Word> wordList = cacheClient.queryListPassThrough(keyPre,page
                ,Word.class,redisProperties.cache_word_time, TimeUnit.MINUTES,this::selectAllByTime);

        Map<String,Object> map = new HashMap<>();
        map.put("words",JSONUtil.toJsonStr(wordList));
        //获取页码总数
        Count count = cacheClient.queryPassThrough(redisProperties.cache_word_page_pre, SessionHolder.getUser()
                ,Count.class,redisProperties.cache_word_time, TimeUnit.MINUTES,this::selectCount);
        map.put("pageCount", count.getCount());
        return Result.success(map);
    }

    private List<Word> selectAllByTime(Integer page){
        return wordMapper.selectAllByUpdateTime(SessionHolder.getUser(),(page-1)* dicProperties.page_capacity,dicProperties.page_capacity);
    }

    private Count selectCount(Long uid){
        int count = lambdaQuery().eq(Word::getUid,uid).count();
        return new Count(count/ dicProperties.page_capacity + (count% dicProperties.page_capacity >0 ?1 :0));
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取单词表，根据统计
    **/
    public Result getWordsByCount(Integer page){
        if(DataUtils.isNaturalNumInvalid(page)){
            return Result.failed(ResultCode.FAILED_PARAMS_VALIDATE);
        }
        String keyPre =redisProperties.cache_word_byCount_pre+ SessionHolder.getUser()+":";

        List<Word> wordList = cacheClient.queryListPassThrough(keyPre,page
                ,Word.class,redisProperties.cache_word_time, TimeUnit.MINUTES,this::selectAllByCount);
        Map<String,Object> map = new HashMap<>();
        map.put("words",JSONUtil.toJsonStr(wordList));
        //获取页码总数
        Count count = cacheClient.queryPassThrough(redisProperties.cache_word_page_pre, SessionHolder.getUser()
                , Count.class,redisProperties.cache_word_time, TimeUnit.MINUTES,this::selectCount);
        map.put("pageCount",count.getCount());
        return Result.success(map);
    }

    private List<Word> selectAllByCount(Integer page){
        return wordMapper.selectAllByCount(SessionHolder.getUser(),(page-1)*dicProperties.page_capacity,dicProperties.page_capacity);
    }
    
    private void initWord(Word word){
        if(word.getUid() == null){
            word.setUid(SessionHolder.getUser());
        }
        if(word.getWord() == null){
            word.setWord("");
        }
        if(word.getTranslation() == null){
            word.setTranslation("");
        }
        if(word.getPhonetic() == null){
            word.setPhonetic("");
        }
        if(word.getNature() == null){
            word.setNature("");
        }
        if(word.getRemark() == null){
            word.setRemark("");
        }
        if(word.getCount() == null){
            word.setCount(1);
        }
        if(word.getCreateTime() == null){
            word.setCreateTime(new Date());
        }
        if(word.getUpdateTime() == null){
            word.setUpdateTime(new Date());
        }
    }

    private String convertTagToName(String tag) {
        switch (tag) {
            case "NN": return "名词";
            case "NNS": return "名词(复数)";
            case "NNP": return "专有名词";
            case "NNPS": return "专有名词(复数)";
            case "VB": return "动词(基本形式)";
            case "VBD": return "动词(过去式)";
            case "VBG": return "动名词/现在分词";
            case "VBN": return "动词(过去分词)";
            case "VBP": return "动词(非第三人称单数现在时)";
            case "VBZ": return "动词(第三人称单数现在时)";
            case "JJ": return "形容词";
            case "JJR": return "比较级形容词";
            case "JJS": return "最高级形容词";
            case "RB": return "副词";
            case "RBR": return "比较级副词";
            case "RBS": return "最高级副词";
            case "PRP": return "人称代词";
            case "PRP$": return "所有格代词";
            case "WP": return "疑问代词";
            case "WP$": return "所有格疑问代词";
            case "DT": return "限定词";
            case "IN": return "介词";
            case "CC": return "连词";
            case "MD": return "情态动词";
            case "CD": return "数词";
            case "EX": return "存在句代词";
            case "FW": return "外来词";
            case "LS": return "列表标记";
            case "PDT": return "前置限定词";
            case "POS": return "所有格标记";
            case "SYM": return "符号";
            case "UH": return "感叹词";
            case "TO": return "介词";
            default:
                return tag;
        }
    }
}
